package top.korori.sv.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import top.korori.common.bo.MediaVideoFormBo;
import top.korori.common.constant.FileTypeConstant;
import top.korori.common.exception.BizException;
import top.korori.common.bo.MediaPicFormBo;
import top.korori.sv.entity.vo.SvMediaVo;
import top.korori.sv.enums.SvMediaUse;
import top.korori.sv.mapper.SvMediaMapper;
import top.korori.sv.service.SvMediaService;
import top.korori.sv.entity.SvMedia;
import top.korori.sv.uitls.SvSecurityUtil;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Base64;
import java.util.Objects;

/**
 * 
 * 媒体文件 服务实现类
 * 
 *
 * @author korori
 * @since 2023-10-16
 */
@Service
@Log4j2
public class SvMediaServiceImpl extends ServiceImpl<SvMediaMapper, SvMedia> implements SvMediaService {

    @Value("${sv.media.upload-dir}")
    private String uploadDir;

    @Override
    public SvMediaVo uploadPic(MultipartFile multipartFile, MediaPicFormBo mediaPicFormBo, Integer source) {

        String pathPrefix = EnumUtil.getFieldBy(SvMediaUse::getPath, SvMediaUse::getUse, mediaPicFormBo.getUse());
        if (ObjUtil.isNull(pathPrefix)) {
            BizException.cast("文件上传用途不存在");
        }
        String suffixName = Objects.requireNonNull(multipartFile.getOriginalFilename()).substring(multipartFile.getOriginalFilename().lastIndexOf(".")+1);

        if (!Arrays.asList(FileTypeConstant.IMAGE_EXTENSION).contains(suffixName)) {
            BizException.cast("不支持该类型图片");
        }

        if (multipartFile.getSize() > 10 * 1024 * 1024) {
            BizException.cast("图片大小不能超过10mb");
        }

        return copyFileAndSave(multipartFile, source,pathPrefix, suffixName);
    }

    @Override
    public SvMediaVo uploadPic(MultipartFile multipartFile, Integer use, Integer source) {
        MediaPicFormBo mediaVideoFormBo = new MediaPicFormBo();
        mediaVideoFormBo.setUse(use);
        return this.uploadPic(multipartFile,mediaVideoFormBo,source);
    }

    @Override
    public SvMediaVo uploadVideo(MultipartFile multipartFile, MediaVideoFormBo mediaFormBo, Integer source) {

        String pathPrefix = EnumUtil.getFieldBy(SvMediaUse::getPath, SvMediaUse::getUse, mediaFormBo.getUse());
        if (ObjUtil.isNull(pathPrefix)) {
            BizException.cast("文件上传用途不存在");
        }

        String suffixName = Objects.requireNonNull(multipartFile.getOriginalFilename()).substring(multipartFile.getOriginalFilename().lastIndexOf(".") + 1);

        if (!Arrays.asList(FileTypeConstant.VIDEO_EXTENSION).contains(suffixName)) {
            BizException.cast("不支持该类型视频");
        }

        if (multipartFile.getSize() > 1024 * 1024 * 1024) {
            BizException.cast("视频大小不能超过1024mb");
        }

        return copyFileAndSave(multipartFile, source, pathPrefix, suffixName);
    }

    @Override
    public SvMediaVo uploadBase64Pic(MediaPicFormBo mediaFormBo, Integer source) {


        if (ObjUtil.isEmpty(mediaFormBo.getBase64())){
            BizException.cast("base64字符串不能为空");
        }

        String pathPrefix = EnumUtil.getFieldBy(SvMediaUse::getPath, SvMediaUse::getUse, mediaFormBo.getUse());
        if (ObjUtil.isNull(pathPrefix)) {
            BizException.cast("文件上传用途不存在");
        }

        MultipartFile multipartFile = base64ToMultipartFile(mediaFormBo.getBase64());
        return uploadPic(multipartFile,mediaFormBo,source);
    }

    /**
     * @param multipartFile 文件
     * @param source        来源
     * @param pathPrefix    路径分类前缀
     * @param suffixName    后缀名
     * @return 文件信息
     */
    private SvMediaVo copyFileAndSave(MultipartFile multipartFile, Integer source, String pathPrefix, String suffixName) {
        String fileName = IdUtil.fastSimpleUUID();

        String md5 = null;

        FileOutputStream fileOutputStream = null;
        InputStream copyInputStream = null;
        InputStream md5InputStream = null;

        try {
            File file = new File(uploadDir + "/" + pathPrefix + "/" + fileName + "."+ suffixName);

            if (!file.exists() && !file.getParentFile().exists()) {
                    file.getParentFile().mkdirs();
            }

            fileOutputStream = new FileOutputStream(file);
            copyInputStream = multipartFile.getInputStream();
            md5InputStream = multipartFile.getInputStream();

            md5 = DigestUtil.md5Hex(md5InputStream);
            IoUtil.copy(copyInputStream, fileOutputStream);
        } catch (IOException e) {
            log.error("上传失败,出现io异常,异常信息: {}", e.getMessage());
            BizException.cast("上传失败:系统异常");
        }finally {
            try {
                if (fileOutputStream != null) {
                    fileOutputStream.close();
                }
                if (copyInputStream != null) {
                    copyInputStream.close();
                }
                if (md5InputStream != null) {
                    md5InputStream.close();
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        SvMedia dbMedia = this.lambdaQuery().eq(SvMedia::getMd5, md5).one();
        if (ObjUtil.isNotNull(dbMedia)) {
            return BeanUtil.copyProperties(dbMedia, SvMediaVo.class);
        }
        SvMedia svMedia = new SvMedia();
        svMedia.setMd5(md5);
        svMedia.setSize(multipartFile.getSize());
        svMedia.setSource(source);
        svMedia.setUserId(SvSecurityUtil.getUserId());
        svMedia.setType(multipartFile.getContentType());
        svMedia.setUrl("/" + pathPrefix + "/" + fileName +"."+ suffixName);
        this.save(svMedia);
        return BeanUtil.copyProperties(svMedia, SvMediaVo.class);
    }

    public MultipartFile base64ToMultipartFile(String base64) {
        String[] parts = base64.split(",");
        String contentType = parts[0].split(";")[0].split(":")[1];
        boolean isImg = Arrays.asList(FileTypeConstant.IMAGE_CONTENT_TYPE).contains(contentType);
        if (!isImg){
            BizException.cast("不支持该类型文件");
        }
        byte[] bytes = Base64.getDecoder().decode(parts[1]);
        return new MockMultipartFile("file", IdUtil.fastSimpleUUID()+"."+contentType.split("/")[1], contentType, bytes);
    }


}
